﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using UnityEngine;

namespace JH
{
    /// <summary>
    ///  便捷调用的方法库
    /// </summary>
    public readonly partial struct JTask
    {
        /// <summary>
        ///  等待直到条件满足
        /// </summary>
        public static ConditionAwaiter WaitUntil(Func<bool> condition, CancellationToken token = default)
        {
            // 如果条件为空，则直接返回true
            if (condition == null) return new ConditionAwaiter(() => true, token);
            return new ConditionAwaiter(condition, token);
        }

        /// <summary>
        ///  等待一帧
        /// </summary>
        public static ConditionAwaiter Yield(CancellationToken token = default)
        {
            var currentFrameCount = ThreadDispatcher.FrameCount;
            return new ConditionAwaiter(() => ThreadDispatcher.FrameCount > currentFrameCount, token);
        }

        /// <summary>
        ///  等待返回主线程
        /// </summary>
        public static ConditionAwaiter SwitchToMainThread(CancellationToken token = default)
        {
            return new ConditionAwaiter(() => ThreadDispatcher.IsMainThread, token, DispatchState.MainThread);
        }

        public static ConditionAwaiter SwitchToOtherThread(CancellationToken token = default)
        {
            return new ConditionAwaiter(() => !ThreadDispatcher.IsMainThread, token, DispatchState.OtherThread);
        }

        /// <summary>
        ///  延时
        /// </summary>
        public static ConditionAwaiter WaitForSeconds(float seconds, CancellationToken token = default)
        {
            // 如果时间小于等于0，则直接返回true
            if (seconds <= 0) return new ConditionAwaiter(() => true, token);

            // 利用stopwatch计时
            var watch = StopWatchPool.Get();
            watch.Start();
            return new ConditionAwaiter(() =>
            {
                // 如果时间超过指定时间，则返回true
                var ret = watch.ElapsedMilliseconds >= seconds * 1000;
                // 回收计时器
                if (ret) StopWatchPool.Release(watch);
                // 返回结果
                return ret;
            }, token);
        }

        /// <summary>
        ///  任意一个任务完成
        /// </summary>
        public static ConditionAwaiter WhenAny(CancellationToken token, params JTask[] tasks)
        {
            if (tasks == null || tasks.Length == 0) return new ConditionAwaiter(() => true);
            return new ConditionAwaiter(() => tasks.Any(task => task.GetAwaiter().IsCompleted), token);
        }

        /// <summary>
        ///  任意一个任务完成
        /// </summary>
        public static ConditionAwaiter WhenAny(IEnumerable<JTask> tasks, CancellationToken token)
        {
            return WhenAny(token, tasks.ToArray());
        }

        /// <summary>
        ///  任意一个任务完成
        /// </summary>
        public static ConditionAwaiter WhenAny(CancellationToken token, params ConditionAwaiter[] tasks)
        {
            if (tasks == null || tasks.Length == 0) return new ConditionAwaiter(() => true);
            return new ConditionAwaiter(() => tasks.Any(awaiter => awaiter.IsCompleted), token);
        }

        /// <summary>
        ///  任意一个任务完成
        /// </summary>
        public static ConditionAwaiter WhenAny(IEnumerable<ConditionAwaiter> awaiters,
            CancellationToken token)
        {
            return WhenAny(token, awaiters.ToArray());
        }


        /// <summary>
        ///  所有任务完成
        /// </summary>
        public static ConditionAwaiter WhenAll(CancellationToken token = default, params JTask[] tasks)
        {
            if (tasks == null || tasks.Length == 0) return new ConditionAwaiter(() => true);
            return WhenAll(tasks.Select(i=>i.GetAwaiter()), token);
        }

        /// <summary>
        ///  所有任务完成
        /// </summary>
        public static ConditionAwaiter WhenAll(IEnumerable<JTask> tasks, CancellationToken token = default)
        {
            return WhenAll(token, tasks.ToArray());
        }

        /// <summary>
        ///  所有任务完成
        /// </summary>
        public static ConditionAwaiter WhenAll(CancellationToken token = default, params ConditionAwaiter[] awaiters)
        {
            if (awaiters == null || awaiters.Length == 0) return new ConditionAwaiter(() => true);
            return new ConditionAwaiter(() => awaiters.All(awaiter => awaiter.IsCompleted), token);
        }

        /// <summary>
        ///  所有任务完成
        /// </summary>
        public static ConditionAwaiter WhenAll(IEnumerable<ConditionAwaiter> awaiters,
            CancellationToken token = default)
        {
            return WhenAll(token, awaiters.ToArray());
        }

        /// <summary>
        ///  完成任务
        /// </summary>
        public static JTask CompletedTask => new(() => true);
    }
}